﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace OpenPhotoAlbum.Controls.PhotoProcessors
{
    public class Sketch : IPhotoProcessor
    {
        private float _thresholdLevel1 = 0.21f;
        private float _thresholdLevel2 = 0.19f;

        protected void SetThreshold(float level1, float level2)
        {
            _thresholdLevel1 = level1;
            _thresholdLevel2 = level2;
        }

        #region IPhotoProcessor Members

        public byte[] Process(byte[] input)
        {
            MemoryStream ms = new MemoryStream(input);
            Bitmap source = new Bitmap(ms);

            int width = source.Width;
            int height = source.Height;

			DateTime t1 = DateTime.UtcNow;

            Color[,] srcMatrix = new Color[height, width];

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    srcMatrix[y, x] = source.GetPixel(x, y);
                }
            }

			DateTime t2 = DateTime.UtcNow;

            // first pass
            //
            Color[,] tgtMatrix = new Color[height, width];
            int finalValue;
            float currentValue;
            List<Color> neighbors = new List<Color>(4);
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    Color src = srcMatrix[y, x];
                    currentValue = src.GetBrightness();

                    neighbors.Clear();

                    if (x > 0) { neighbors.Add(srcMatrix[y, x - 1]); }
                    if (x < width - 1) { neighbors.Add(srcMatrix[y, x + 1]); }
                    if (y > 0) { neighbors.Add(srcMatrix[y - 1, x]); }
                    if (y < height - 1) { neighbors.Add(srcMatrix[y + 1, x]); }

                    
                    float diff = 0;
                    foreach (Color color in neighbors)
                    {
                        diff += Math.Abs(color.GetBrightness() - currentValue);
                    }
                    if (diff > _thresholdLevel1)
                    {
                        finalValue = 0;
                    }
                    else if (diff > _thresholdLevel2)
                    {
                        finalValue = 172;
                    }
                    else
                    {
                        finalValue = 255;
                    }

                    tgtMatrix[y, x] = Color.FromArgb(finalValue, finalValue, finalValue); 
                }
            }

            // second pass
            //
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    Color src = tgtMatrix[y, x];
                    currentValue = src.GetBrightness();

                    neighbors.Clear();

                    if (x > 0) { neighbors.Add(tgtMatrix[y, x - 1]); }
                    if (x < width - 1) { neighbors.Add(tgtMatrix[y, x + 1]); }
                    if (y > 0) { neighbors.Add(tgtMatrix[y - 1, x]); }
                    if (y < height - 1) { neighbors.Add(tgtMatrix[y + 1, x]); }


                    int count = 0;
                    foreach (Color color in neighbors)
                    {
                        if (color.GetBrightness() == 0) { count++; }
                    }
                    if (count < 2) { tgtMatrix[y, x] = Color.FromArgb(255, 255, 255); }
                }
            }

			DateTime t3 = DateTime.UtcNow;

            Bitmap canvas = new Bitmap(width, height);
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    canvas.SetPixel(x, y, tgtMatrix[y, x]);
                }
            }

			DateTime t4 = DateTime.UtcNow;
            System.Diagnostics.Debug.WriteLine(t2.Subtract(t1).TotalMilliseconds);
            System.Diagnostics.Debug.WriteLine(t3.Subtract(t2).TotalMilliseconds);
            System.Diagnostics.Debug.WriteLine(t4.Subtract(t3).TotalMilliseconds);

            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

            //find the encoder with the image/jpeg mime-type
            ImageCodecInfo ici = null;
            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.MimeType == "image/jpeg")
                    ici = codec;
            }

            EncoderParameters ep = new EncoderParameters();
            ep.Param[0] = new EncoderParameter(Encoder.Quality, (long)90);

            MemoryStream msResult = new MemoryStream();
            canvas.Save(msResult, ici, ep);

            canvas.Dispose();
            source.Dispose();
            ms.Close();

            return msResult.ToArray();
        }

        #endregion
    }

}
